home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1994 David I. Bell
- * Permission is granted to use, distribute, or modify this source,
- * provided that this copyright notice remains intact.
- *
- * Extended precision rational arithmetic primitive routines
- */
-
- #include "qmath.h"
-
-
- NUMBER _qzero_ = { { _zeroval_, 1, 0 }, { _oneval_, 1, 0 }, 1 };
- NUMBER _qone_ = { { _oneval_, 1, 0 }, { _oneval_, 1, 0 }, 1 };
- static NUMBER _qtwo_ = { { _twoval_, 1, 0 }, { _oneval_, 1, 0 }, 1 };
- static NUMBER _qten_ = { { _tenval_, 1, 0 }, { _oneval_, 1, 0 }, 1 };
- NUMBER _qnegone_ = { { _oneval_, 1, 1 }, { _oneval_, 1, 0 }, 1 };
- NUMBER _qonehalf_ = { { _oneval_, 1, 0 }, { _twoval_, 1, 0 }, 1 };
-
-
- /*
- * Create another copy of a number.
- * q2 = qcopy(q1);
- */
- NUMBER *
- qcopy(q)
- register NUMBER *q;
- {
- register NUMBER *r;
-
- r = qalloc();
- r->num.sign = q->num.sign;
- if (!zisunit(q->num)) {
- r->num.len = q->num.len;
- r->num.v = alloc(r->num.len);
- zcopyval(q->num, r->num);
- }
- if (!zisunit(q->den)) {
- r->den.len = q->den.len;
- r->den.v = alloc(r->den.len);
- zcopyval(q->den, r->den);
- }
- return r;
- }
-
-
- /*
- * Convert a number to a normal integer.
- * i = qtoi(q);
- */
- long
- qtoi(q)
- register NUMBER *q;
- {
- long i;
- ZVALUE res;
-
- if (qisint(q))
- return ztoi(q->num);
- zquo(q->num, q->den, &res);
- i = ztoi(res);
- zfree(res);
- return i;
- }
-
-
- /*
- * Convert a normal integer into a number.
- * q = itoq(i);
- */
- NUMBER *
- itoq(i)
- long i;
- {
- register NUMBER *q;
-
- if ((i >= -1) && (i <= 10)) {
- switch ((int) i) {
- case 0: q = &_qzero_; break;
- case 1: q = &_qone_; break;
- case 2: q = &_qtwo_; break;
- case 10: q = &_qten_; break;
- case -1: q = &_qnegone_; break;
- default: q = NULL;
- }
- if (q)
- return qlink(q);
- }
- q = qalloc();
- itoz(i, &q->num);
- return q;
- }
-
-
- /*
- * Convert a number to a normal unsigned integer.
- * u = qtou(q);
- */
- FULL
- qtou(q)
- register NUMBER *q;
- {
- FULL i;
- ZVALUE res;
-
- if (qisint(q))
- return ztou(q->num);
- zquo(q->num, q->den, &res);
- i = ztou(res);
- zfree(res);
- return i;
- }
-
-
- /*
- * Convert a normal unsigned integer into a number.
- * q = utoq(i);
- */
- NUMBER *
- utoq(i)
- FULL i;
- {
- register NUMBER *q;
-
- if (i <= 10) {
- switch ((int) i) {
- case 0: q = &_qzero_; break;
- case 1: q = &_qone_; break;
- case 2: q = &_qtwo_; break;
- case 10: q = &_qten_; break;
- default: q = NULL;
- }
- if (q)
- return qlink(q);
- }
- q = qalloc();
- utoz(i, &q->num);
- return q;
- }
-
-
- /*
- * Create a number from the given integral numerator and denominator.
- * q = iitoq(inum, iden);
- */
- NUMBER *
- iitoq(inum, iden)
- long inum, iden;
- {
- register NUMBER *q;
- long d;
- BOOL sign;
-
- if (iden == 0)
- math_error("Division by zero");
- if (inum == 0)
- return qlink(&_qzero_);
- sign = 0;
- if (inum < 0) {
- sign = 1;
- inum = -inum;
- }
- if (iden < 0) {
- sign = 1 - sign;
- iden = -iden;
- }
- d = iigcd(inum, iden);
- inum /= d;
- iden /= d;
- if (iden == 1)
- return itoq(sign ? -inum : inum);
- q = qalloc();
- if (inum != 1)
- itoz(inum, &q->num);
- itoz(iden, &q->den);
- q->num.sign = sign;
- return q;
- }
-
-
- /*
- * Add two numbers to each other.
- * q3 = qadd(q1, q2);
- */
- NUMBER *
- qadd(q1, q2)
- register NUMBER *q1, *q2;
- {
- NUMBER *r;
- ZVALUE t1, t2, temp, d1, d2, vpd1, upd1;
-
- if (qiszero(q1))
- return qlink(q2);
- if (qiszero(q2))
- return qlink(q1);
- r = qalloc();
- /*
- * If either number is an integer, then the result is easy.
- */
- if (qisint(q1) && qisint(q2)) {
- zadd(q1->num, q2->num, &r->num);
- return r;
- }
- if (qisint(q2)) {
- zmul(q1->den, q2->num, &temp);
- zadd(q1->num, temp, &r->num);
- zfree(temp);
- zcopy(q1->den, &r->den);
- return r;
- }
- if (qisint(q1)) {
- zmul(q2->den, q1->num, &temp);
- zadd(q2->num, temp, &r->num);
- zfree(temp);
- zcopy(q2->den, &r->den);
- return r;
- }
- /*
- * Both arguments are true fractions, so we need more work.
- * If the denominators are relatively prime, then the answer is the
- * straightforward cross product result with no need for reduction.
- */
- zgcd(q1->den, q2->den, &d1);
- if (zisunit(d1)) {
- zfree(d1);
- zmul(q1->num, q2->den, &t1);
- zmul(q1->den, q2->num, &t2);
- zadd(t1, t2, &r->num);
- zfree(t1);
- zfree(t2);
- zmul(q1->den, q2->den, &r->den);
- return r;
- }
- /*
- * The calculation is now more complicated.
- * See Knuth Vol 2 for details.
- */
- zquo(q2->den, d1, &vpd1);
- zquo(q1->den, d1, &upd1);
- zmul(q1->num, vpd1, &t1);
- zmul(q2->num, upd1, &t2);
- zadd(t1, t2, &temp);
- zfree(t1);
- zfree(t2);
- zfree(vpd1);
- zgcd(temp, d1, &d2);
- zfree(d1);
- if (zisunit(d2)) {
- zfree(d2);
- r->num = temp;
- zmul(upd1, q2->den, &r->den);
- zfree(upd1);
- return r;
- }
- zquo(temp, d2, &r->num);
- zfree(temp);
- zquo(q2->den, d2, &temp);
- zfree(d2);
- zmul(temp, upd1, &r->den);
- zfree(temp);
- zfree(upd1);
- return r;
- }
-
-
- /*
- * Subtract one number from another.
- * q3 = qsub(q1, q2);
- */
- NUMBER *
- qsub(q1, q2)
- register NUMBER *q1, *q2;
- {
- NUMBER *r;
-
- if (q1 == q2)
- return qlink(&_qzero_);
- if (qiszero(q2))
- return qlink(q1);
- if (qisint(q1) && qisint(q2)) {
- r = qalloc();
- zsub(q1->num, q2->num, &r->num);
- return r;
- }
- q2 = qneg(q2);
- if (qiszero(q1))
- return q2;
- r = qadd(q1, q2);
- qfree(q2);
- return r;
- }
-
-
- /*
- * Increment a number by one.
- */
- NUMBER *
- qinc(q)
- NUMBER *q;
- {
- NUMBER *r;
-
- r = qalloc();
- if (qisint(q)) {
- zadd(q->num, _one_, &r->num);
- return r;
- }
- zadd(q->num, q->den, &r->num);
- zcopy(q->den, &r->den);
- return r;
- }
-
-
- /*
- * Decrement a number by one.
- */
- NUMBER *
- qdec(q)
- NUMBER *q;
- {
- NUMBER *r;
-
- r = qalloc();
- if (qisint(q)) {
- zsub(q->num, _one_, &r->num);
- return r;
- }
- zsub(q->num, q->den, &r->num);
- zcopy(q->den, &r->den);
- return r;
- }
-
-
- /*
- * Add a normal small integer value to an arbitrary number.
- */
- NUMBER *
- qaddi(q1, n)
- NUMBER *q1;
- long n;
- {
- NUMBER addnum; /* temporary number */
- HALF addval[2]; /* value of small number */
- BOOL neg; /* TRUE if number is neg */
-
- if (n == 0)
- return qlink(q1);
- if (n == 1)
- return qinc(q1);
- if (n == -1)
- return qdec(q1);
- if (qiszero(q1))
- return itoq(n);
- addnum.num.sign = 0;
- addnum.num.len = 1;
- addnum.num.v = addval;
- addnum.den = _one_;
- neg = (n < 0);
- if (neg)
- n = -n;
- addval[0] = (HALF) n;
- n = (((FULL) n) >> BASEB);
- if (n) {
- addval[1] = (HALF) n;
- addnum.num.len = 2;
- }
- if (neg)
- return qsub(q1, &addnum);
- else
- return qadd(q1, &addnum);
- }
-
-
- /*
- * Multiply two numbers.
- * q3 = qmul(q1, q2);
- */
- NUMBER *
- qmul(q1, q2)
- register NUMBER *q1, *q2;
- {
- NUMBER *r; /* returned value */
- ZVALUE n1, n2, d1, d2; /* numerators and denominators */
- ZVALUE tmp;
-
- if (qiszero(q1) || qiszero(q2))
- return qlink(&_qzero_);
- if (qisone(q1))
- return qlink(q2);
- if (qisone(q2))
- return qlink(q1);
- if (qisint(q1) && qisint(q2)) { /* easy results if integers */
- r = qalloc();
- zmul(q1->num, q2->num, &r->num);
- return r;
- }
- n1 = q1->num;
- n2 = q2->num;
- d1 = q1->den;
- d2 = q2->den;
- if (ziszero(d1) || ziszero(d2))
- math_error("Division by zero");
- if (ziszero(n1) || ziszero(n2))
- return qlink(&_qzero_);
- if (!zisunit(n1) && !zisunit(d2)) { /* possibly reduce */
- zgcd(n1, d2, &tmp);
- if (!zisunit(tmp)) {
- zquo(q1->num, tmp, &n1);
- zquo(q2->den, tmp, &d2);
- }
- zfree(tmp);
- }
- if (!zisunit(n2) && !zisunit(d1)) { /* again possibly reduce */
- zgcd(n2, d1, &tmp);
- if (!zisunit(tmp)) {
- zquo(q2->num, tmp, &n2);
- zquo(q1->den, tmp, &d1);
- }
- zfree(tmp);
- }
- r = qalloc();
- zmul(n1, n2, &r->num);
- zmul(d1, d2, &r->den);
- if (q1->num.v != n1.v)
- zfree(n1);
- if (q1->den.v != d1.v)
- zfree(d1);
- if (q2->num.v != n2.v)
- zfree(n2);
- if (q2->den.v != d2.v)
- zfree(d2);
- return r;
- }
-
-
- /*
- * Multiply a number by a small integer.
- * q2 = qmuli(q1, n);
- */
- NUMBER *
- qmuli(q, n)
- NUMBER *q;
- long n;
- {
- NUMBER *r;
- long d; /* gcd of multiplier and denominator */
- int sign;
-
- if ((n == 0) || qiszero(q))
- return qlink(&_qzero_);
- if (n == 1)
- return qlink(q);
- r = qalloc();
- if (qisint(q)) {
- zmuli(q->num, n, &r->num);
- return r;
- }
- sign = 1;
- if (n < 0) {
- n = -n;
- sign = -1;
- }
- d = zmodi(q->den, n);
- d = iigcd(d, n);
- zmuli(q->num, (n * sign) / d, &r->num);
- (void) zdivi(q->den, d, &r->den);
- return r;
- }
-
-
- /*
- * Divide two numbers (as fractions).
- * q3 = qdiv(q1, q2);
- */
- NUMBER *
- qdiv(q1, q2)
- register NUMBER *q1, *q2;
- {
- NUMBER temp;
-
- if (qiszero(q2))
- math_error("Division by zero");
- if ((q1 == q2) || !qcmp(q1, q2))
- return qlink(&_qone_);
- if (qisone(q1))
- return qinv(q2);
- temp.num = q2->den;
- temp.den = q2->num;
- temp.num.sign = temp.den.sign;
- temp.den.sign = 0;
- temp.links = 1;
- return qmul(q1, &temp);
- }
-
-
- /*
- * Divide a number by a small integer.
- * q2 = qdivi(q1, n);
- */
- NUMBER *
- qdivi(q, n)
- NUMBER *q;
- long n;
- {
- NUMBER *r;
- long d; /* gcd of divisor and numerator */
- int sign;
-
- if (n == 0)
- math_error("Division by zero");
- if ((n == 1) || qiszero(q))
- return qlink(q);
- sign = 1;
- if (n < 0) {
- n = -n;
- sign = -1;
- }
- r = qalloc();
- d = zmodi(q->num, n);
- d = iigcd(d, n);
- (void) zdivi(q->num, d * sign, &r->num);
- zmuli(q->den, n / d, &r->den);
- return r;
- }
-
-
- /*
- * Return the quotient when one number is divided by another.
- * This works for fractional values also, and in all cases:
- * qquo(q1, q2) = int(q1 / q2).
- */
- NUMBER *
- qquo(q1, q2)
- register NUMBER *q1, *q2;
- {
- ZVALUE num, den, res;
- NUMBER *q;
-
- if (zisunit(q1->num))
- num = q2->den;
- else if (zisunit(q2->den))
- num = q1->num;
- else
- zmul(q1->num, q2->den, &num);
- if (zisunit(q1->den))
- den = q2->num;
- else if (zisunit(q2->num))
- den = q1->den;
- else
- zmul(q1->den, q2->num, &den);
- zquo(num, den, &res);
- if ((num.v != q2->den.v) && (num.v != q1->num.v))
- zfree(num);
- if ((den.v != q2->num.v) && (den.v != q1->den.v))
- zfree(den);
- if (ziszero(res)) {
- zfree(res);
- return qlink(&_qzero_);
- }
- res.sign = (q1->num.sign != q2->num.sign);
- if (zisunit(res)) {
- q = (res.sign ? &_qnegone_ : &_qone_);
- zfree(res);
- return qlink(q);
- }
- q = qalloc();
- q->num = res;
- return q;
- }
-
-
- /*
- * Return the absolute value of a number.
- * q2 = qabs(q1);
- */
- NUMBER *
- qabs(q)
- register NUMBER *q;
- {
- register NUMBER *r;
-
- if (q->num.sign == 0)
- return qlink(q);
- r = qalloc();
- if (!zisunit(q->num))
- zcopy(q->num, &r->num);
- if (!zisunit(q->den))
- zcopy(q->den, &r->den);
- r->num.sign = 0;
- return r;
- }
-
-
- /*
- * Negate a number.
- * q2 = qneg(q1);
- */
- NUMBER *
- qneg(q)
- register NUMBER *q;
- {
- register NUMBER *r;
-
- if (qiszero(q))
- return qlink(&_qzero_);
- r = qalloc();
- if (!zisunit(q->num))
- zcopy(q->num, &r->num);
- if (!zisunit(q->den))
- zcopy(q->den, &r->den);
- r->num.sign = !q->num.sign;
- return r;
- }
-
-
- /*
- * Return the sign of a number (-1, 0 or 1)
- */
- NUMBER *
- qsign(q)
- NUMBER *q;
- {
- if (qiszero(q))
- return qlink(&_qzero_);
- if (qisneg(q))
- return qlink(&_qnegone_);
- return qlink(&_qone_);
- }
-
-
- /*
- * Invert a number.
- * q2 = qinv(q1);
- */
- NUMBER *
- qinv(q)
- register NUMBER *q;
- {
- register NUMBER *r;
-
- if (qisunit(q)) {
- r = (qisneg(q) ? &_qnegone_ : &_qone_);
- return qlink(r);
- }
- if (qiszero(q))
- math_error("Division by zero");
- r = qalloc();
- if (!zisunit(q->num))
- zcopy(q->num, &r->den);
- if (!zisunit(q->den))
- zcopy(q->den, &r->num);
- r->num.sign = q->num.sign;
- r->den.sign = 0;
- return r;
- }
-
-
- /*
- * Return just the numerator of a number.
- * q2 = qnum(q1);
- */
- NUMBER *
- qnum(q)
- register NUMBER *q;
- {
- register NUMBER *r;
-
- if (qisint(q))
- return qlink(q);
- if (zisunit(q->num)) {
- r = (qisneg(q) ? &_qnegone_ : &_qone_);
- return qlink(r);
- }
- r = qalloc();
- zcopy(q->num, &r->num);
- return r;
- }
-
-
- /*
- * Return just the denominator of a number.
- * q2 = qden(q1);
- */
- NUMBER *
- qden(q)
- register NUMBER *q;
- {
- register NUMBER *r;
-
- if (qisint(q))
- return qlink(&_qone_);
- r = qalloc();
- zcopy(q->den, &r->num);
- return r;
- }
-
-
- /*
- * Return the fractional part of a number.
- * q2 = qfrac(q1);
- */
- NUMBER *
- qfrac(q)
- register NUMBER *q;
- {
- register NUMBER *r;
- ZVALUE z;
-
- if (qisint(q))
- return qlink(&_qzero_);
- if ((q->num.len < q->den.len) || ((q->num.len == q->den.len) &&
- (q->num.v[q->num.len - 1] < q->den.v[q->num.len - 1])))
- return qlink(q);
- r = qalloc();
- if (qisneg(q)) {
- zmod(q->num, q->den, &z);
- zsub(q->den, z, &r->num);
- zfree(z);
- } else {
- zmod(q->num, q->den, &r->num);
- }
- zcopy(q->den, &r->den);
- r->num.sign = q->num.sign;
- return r;
- }
-
-
- /*
- * Return the integral part of a number.
- * q2 = qint(q1);
- */
- NUMBER *
- qint(q)
- register NUMBER *q;
- {
- register NUMBER *r;
-
- if (qisint(q))
- return qlink(q);
- if ((q->num.len < q->den.len) || ((q->num.len == q->den.len) &&
- (q->num.v[q->num.len - 1] < q->den.v[q->num.len - 1])))
- return qlink(&_qzero_);
- r = qalloc();
- zquo(q->num, q->den, &r->num);
- return r;
- }
-
-
- /*
- * Compute the square of a number.
- */
- NUMBER *
- qsquare(q)
- register NUMBER *q;
- {
- ZVALUE num, den;
-
- if (qiszero(q))
- return qlink(&_qzero_);
- if (qisunit(q))
- return qlink(&_qone_);
- num = q->num;
- den = q->den;
- q = qalloc();
- if (!zisunit(num))
- zsquare(num, &q->num);
- if (!zisunit(den))
- zsquare(den, &q->den);
- return q;
- }
-
-
- /*
- * Shift an integer by a given number of bits. This multiplies the number
- * by the appropriate power of two. Positive numbers shift left, negative
- * ones shift right. Low bits are truncated when shifting right.
- */
- NUMBER *
- qshift(q, n)
- NUMBER *q;
- long n;
- {
- register NUMBER *r;
-
- if (qisfrac(q))
- math_error("Shift of non-integer");
- if (qiszero(q) || (n == 0))
- return qlink(q);
- if (n <= -(q->num.len * BASEB))
- return qlink(&_qzero_);
- r = qalloc();
- zshift(q->num, n, &r->num);
- return r;
- }
-
-
- /*
- * Scale a number by a power of two, as in:
- * ans = q * 2^n.
- * This is similar to shifting, except that fractions work.
- */
- NUMBER *
- qscale(q, pow)
- NUMBER *q;
- long pow;
- {
- long numshift, denshift, tmp;
- NUMBER *r;
-
- if (qiszero(q) || (pow == 0))
- return qlink(q);
- if ((pow > 1000000L) || (pow < -1000000L))
- math_error("Very large scale value");
- numshift = zisodd(q->num) ? 0 : zlowbit(q->num);
- denshift = zisodd(q->den) ? 0 : zlowbit(q->den);
- if (pow > 0) {
- tmp = pow;
- if (tmp > denshift)
- tmp = denshift;
- denshift = -tmp;
- numshift = (pow - tmp);
- } else {
- pow = -pow;
- tmp = pow;
- if (tmp > numshift)
- tmp = numshift;
- numshift = -tmp;
- denshift = (pow - tmp);
- }
- r = qalloc();
- if (numshift)
- zshift(q->num, numshift, &r->num);
- else
- zcopy(q->num, &r->num);
- if (denshift)
- zshift(q->den, denshift, &r->den);
- else
- zcopy(q->den, &r->den);
- return r;
- }
-
-
- /*
- * Return the minimum of two numbers.
- */
- NUMBER *
- qmin(q1, q2)
- NUMBER *q1, *q2;
- {
- if (q1 == q2)
- return qlink(q1);
- if (qrel(q1, q2) > 0)
- q1 = q2;
- return qlink(q1);
- }
-
-
- /*
- * Return the maximum of two numbers.
- */
- NUMBER *
- qmax(q1, q2)
- NUMBER *q1, *q2;
- {
- if (q1 == q2)
- return qlink(q1);
- if (qrel(q1, q2) < 0)
- q1 = q2;
- return qlink(q1);
- }
-
-
- /*
- * Perform the logical OR of two integers.
- */
- NUMBER *
- qor(q1, q2)
- NUMBER *q1, *q2;
- {
- register NUMBER *r;
-
- if (qisfrac(q1) || qisfrac(q2))
- math_error("Non-integers for logical or");
- if ((q1 == q2) || qiszero(q2))
- return qlink(q1);
- if (qiszero(q1))
- return qlink(q2);
- r = qalloc();
- zor(q1->num, q2->num, &r->num);
- return r;
- }
-
-
- /*
- * Perform the logical AND of two integers.
- */
- NUMBER *
- qand(q1, q2)
- NUMBER *q1, *q2;
- {
- register NUMBER *r;
- ZVALUE res;
-
- if (qisfrac(q1) || qisfrac(q2))
- math_error("Non-integers for logical and");
- if (q1 == q2)
- return qlink(q1);
- if (qiszero(q1) || qiszero(q2))
- return qlink(&_qzero_);
- zand(q1->num, q2->num, &res);
- if (ziszero(res)) {
- zfree(res);
- return qlink(&_qzero_);
- }
- r = qalloc();
- r->num = res;
- return r;
- }
-
-
- /*
- * Perform the logical XOR of two integers.
- */
- NUMBER *
- qxor(q1, q2)
- NUMBER *q1, *q2;
- {
- register NUMBER *r;
- ZVALUE res;
-
- if (qisfrac(q1) || qisfrac(q2))
- math_error("Non-integers for logical xor");
- if (q1 == q2)
- return qlink(&_qzero_);
- if (qiszero(q1))
- return qlink(q2);
- if (qiszero(q2))
- return qlink(q1);
- zxor(q1->num, q2->num, &res);
- if (ziszero(res)) {
- zfree(res);
- return qlink(&_qzero_);
- }
- r = qalloc();
- r->num = res;
- return r;
- }
-
-
- #if 0
- /*
- * Return the number whose binary representation only has the specified
- * bit set (counting from zero). This thus produces a given power of two.
- */
- NUMBER *
- qbitvalue(n)
- long n;
- {
- register NUMBER *r;
-
- if (n <= 0)
- return qlink(&_qone_);
- r = qalloc();
- zbitvalue(n, &r->num);
- return r;
- }
-
-
- /*
- * Test to see if the specified bit of a number is on (counted from zero).
- * Returns TRUE if the bit is set, or FALSE if it is not.
- * i = qbittest(q, n);
- */
- BOOL
- qbittest(q, n)
- register NUMBER *q;
- long n;
- {
- int x, y;
-
- if ((n < 0) || (n >= (q->num.len * BASEB)))
- return FALSE;
- x = q->num.v[n / BASEB];
- y = (1 << (n % BASEB));
- return ((x & y) != 0);
- }
- #endif
-
-
- /*
- * Return the precision of a number (usually for examining an epsilon value).
- * The precision of a number e less than 1 is the positive
- * integer p for which e = 2^-p * f, where 1 <= f < 2.
- * Numbers greater than or equal to one have a precision of zero.
- * For example, the precision of e is 6 if 1/64 <= e < 1/32.
- */
- long
- qprecision(q)
- NUMBER *q;
- {
- long r;
-
- if (qiszero(q) || qisneg(q))
- math_error("Non-positive number for precision");
- r = - qilog2(q);
- return (r < 0 ? 0 : r);
- }
-
-
- #if 0
- /*
- * Return an integer indicating the sign of a number (-1, 0, or 1).
- * i = qtst(q);
- */
- FLAG
- qtest(q)
- register NUMBER *q;
- {
- if (!ztest(q->num))
- return 0;
- if (q->num.sign)
- return -1;
- return 1;
- }
- #endif
-
-
- /*
- * Determine whether or not one number exactly divides another one.
- * Returns TRUE if the first number is an integer multiple of the second one.
- */
- BOOL
- qdivides(q1, q2)
- NUMBER *q1, *q2;
- {
- if (qiszero(q1))
- return TRUE;
- if (qisint(q1) && qisint(q2)) {
- if (qisunit(q2))
- return TRUE;
- return zdivides(q1->num, q2->num);
- }
- return zdivides(q1->num, q2->num) && zdivides(q2->den, q1->den);
- }
-
-
- /*
- * Compare two numbers and return an integer indicating their relative size.
- * i = qrel(q1, q2);
- */
- FLAG
- qrel(q1, q2)
- register NUMBER *q1, *q2;
- {
- ZVALUE z1, z2;
- long wc1, wc2;
- int sign;
- int z1f = 0, z2f = 0;
-
- if (q1 == q2)
- return 0;
- sign = q2->num.sign - q1->num.sign;
- if (sign)
- return sign;
- if (qiszero(q2))
- return !qiszero(q1);
- if (qiszero(q1))
- return -1;
- /*
- * Make a quick comparison by calculating the number of words resulting as
- * if we multiplied through by the denominators, and then comparing the
- * word counts.
- */
- sign = 1;
- if (qisneg(q1))
- sign = -1;
- wc1 = q1->num.len + q2->den.len;
- wc2 = q2->num.len + q1->den.len;
- if (wc1 < wc2 - 1)
- return -sign;
- if (wc2 < wc1 - 1)
- return sign;
- /*
- * Quick check failed, must actually do the full comparison.
- */
- if (zisunit(q2->den))
- z1 = q1->num;
- else if (zisone(q1->num))
- z1 = q2->den;
- else {
- z1f = 1;
- zmul(q1->num, q2->den, &z1);
- }
- if (zisunit(q1->den))
- z2 = q2->num;
- else if (zisone(q2->num))
- z2 = q1->den;
- else {
- z2f = 1;
- zmul(q2->num, q1->den, &z2);
- }
- sign = zrel(z1, z2);
- if (z1f)
- zfree(z1);
- if (z2f)
- zfree(z2);
- return sign;
- }
-
-
- /*
- * Compare two numbers to see if they are equal.
- * This differs from qrel in that the numbers are not ordered.
- * Returns TRUE if they differ.
- */
- BOOL
- qcmp(q1, q2)
- register NUMBER *q1, *q2;
- {
- if (q1 == q2)
- return FALSE;
- if ((q1->num.sign != q2->num.sign) || (q1->num.len != q2->num.len) ||
- (q2->den.len != q2->den.len) || (*q1->num.v != *q2->num.v) ||
- (*q1->den.v != *q2->den.v))
- return TRUE;
- if (zcmp(q1->num, q2->num))
- return TRUE;
- if (qisint(q1))
- return FALSE;
- return zcmp(q1->den, q2->den);
- }
-
-
- /*
- * Compare a number against a normal small integer.
- * Returns 1, 0, or -1, according to whether the first number is greater,
- * equal, or less than the second number.
- * n = qreli(q, n);
- */
- FLAG
- qreli(q, n)
- NUMBER *q;
- long n;
- {
- int sign;
- ZVALUE num;
- HALF h2[2];
- NUMBER q2;
-
- sign = ztest(q->num); /* do trivial sign checks */
- if (sign == 0) {
- if (n > 0)
- return -1;
- return (n < 0);
- }
- if ((sign < 0) && (n >= 0))
- return -1;
- if ((sign > 0) && (n <= 0))
- return 1;
- n *= sign;
- if (n == 1) { /* quick check against 1 or -1 */
- num = q->num;
- num.sign = 0;
- return (sign * zrel(num, q->den));
- }
- num.sign = (sign < 0);
- num.len = 1 + (n >= BASE);
- num.v = h2;
- h2[0] = (n & BASE1);
- h2[1] = (n >> BASEB);
- if (zisunit(q->den)) /* integer compare if no denominator */
- return zrel(q->num, num);
- q2.num = num;
- q2.den = _one_;
- q2.links = 1;
- return qrel(q, &q2); /* full fractional compare */
- }
-
-
- /*
- * Compare a number against a small integer to see if they are equal.
- * Returns TRUE if they differ.
- */
- BOOL
- qcmpi(q, n)
- NUMBER *q;
- long n;
- {
- long len;
-
- len = q->num.len;
- if ((len > 2) || qisfrac(q) || (q->num.sign != (n < 0)))
- return TRUE;
- if (n < 0)
- n = -n;
- if (((HALF)(n)) != q->num.v[0])
- return TRUE;
- n = ((FULL) n) >> BASEB;
- return (((n != 0) != (len == 2)) || (n != q->num.v[1]));
- }
-
-
- /*
- * Number node allocation routines
- */
-
- #define NNALLOC 1000
-
- union allocNode {
- NUMBER num;
- union allocNode *link;
- };
-
- static union allocNode *freeNum;
-
-
- NUMBER *
- qalloc()
- {
- register union allocNode *temp;
-
- if (freeNum == NULL) {
- freeNum = (union allocNode *)
- malloc(sizeof (NUMBER) * NNALLOC);
- if (freeNum == NULL)
- math_error("Not enough memory");
- freeNum[NNALLOC-1].link = NULL;
- for (temp=freeNum+NNALLOC-2; temp >= freeNum; --temp) {
- temp->link = temp+1;
- }
- }
- temp = freeNum;
- freeNum = temp->link;
- temp->num.links = 1;
- temp->num.num = _one_;
- temp->num.den = _one_;
- return &temp->num;
- }
-
-
- void
- qfreenum(q)
- register NUMBER *q;
- {
- union allocNode *a;
-
- if (q == NULL)
- return;
- zfree(q->num);
- zfree(q->den);
- a = (union allocNode *) q;
- a->link = freeNum;
- freeNum = a;
- }
-
- /* END CODE */
-